﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using DevExpress.XtraBars;
using CTEM.Models;
using CTEM.Controllers.BUS;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraEditors.DXErrorProvider;
using DevExpress.XtraEditors;
using CTEM.Controllers.Global;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid.Views.Grid;

namespace CTEM.ModuleForms.ManagePurchaseBook
{
    public partial class PurchaseBookManagement : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        private readonly PurchaseBookBUS _purchaseBookBUS = new PurchaseBookBUS();
        private List<CT_PurchaseBookDTO> _listSubcons = new List<CT_PurchaseBookDTO>();
        private readonly List<CT_PurchaseBookDTO> _listHistory = new List<CT_PurchaseBookDTO>();
        private bool _isNew;
        private bool _isAllowEdit;
        public PurchaseBookManagement()
        {
            InitializeComponent();
        }

        private void PurchaseBookManagement_Load(object sender, EventArgs e)
        {
            Global.InitLayoutGridView(gridViewPurchaseBook);
            _isAllowEdit = true;
            AllowEditorNot();
            SetItemShortCut();
            LoadRepositoryItems();
            LoadActivePurchaseBook();
        }

        private void SetItemShortCut()
        {
            barButtonItemDelete.ItemShortcut = new BarShortcut((Keys.Control | Keys.D));
            barButtonItemAllowEdit.ItemShortcut = new BarShortcut((Keys.Control | Keys.E));
            barButtonItemUndo.ItemShortcut = new BarShortcut((Keys.Control | Keys.Z));
            barButtonItemRedo.ItemShortcut = new BarShortcut((Keys.Control | Keys.Y));
            barButtonItemRefresh.ItemShortcut = new BarShortcut((Keys.F5));
        }

        private void barButtonItemLoadAll_ItemClick(object sender, ItemClickEventArgs e)
        {
            LoadRepositoryItems();
            LoadAllPurchaseBook();
        }

        private void barButtonItemRefresh_ItemClick(object sender, ItemClickEventArgs e)
        {
            LoadRepositoryItems();
            LoadActivePurchaseBook();
        }

        private void barButtonItemDelete_ItemClick(object sender, ItemClickEventArgs e)
        {
            DeletePurchaseBook();
        }

        private void barButtonItemUndo_ItemClick(object sender, ItemClickEventArgs e)
        {
            Undo();
        }

        private void barButtonItemRedo_ItemClick(object sender, ItemClickEventArgs e)
        {
            Redo();
        }

        /// <summary>
        /// Allow User can edit or not
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void barButtonItemAllowEdit_ItemClick(object sender, ItemClickEventArgs e)
        {
            AllowEditorNot();
        }

        /// <summary>
        /// Always allow User add new PurchaseBook when allow edit or disable edit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewPurchaseBook_FocusedRowChanged(object sender, FocusedRowChangedEventArgs e)
        {
            if (e.FocusedRowHandle == GridControl.NewItemRowHandle)
            {
                gridViewPurchaseBook.OptionsBehavior.Editable = true;
            }
            else
            {
                gridViewPurchaseBook.OptionsBehavior.Editable = _isAllowEdit;
            }
        }

        /// <summary>
        /// Set isNew to make sure User want to create new PurchaseBook
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewPurchaseBook_InitNewRow(object sender, InitNewRowEventArgs e)
        {
            _isNew = true;
        }

        /// <summary>
        /// Make ExceptionMode is NoAction that's to custom control action when exception thew
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewPurchaseBook_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
        {
            e.ExceptionMode = ExceptionMode.NoAction;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewPurchaseBook_InvalidValueException(object sender, InvalidValueExceptionEventArgs e)
        {
            e.ErrorText = Constants.INVALIDATE_VALUE;
            e.ExceptionMode = ExceptionMode.DisplayError;
        }

        /// <summary>
        /// Add new PurchaseBook by validate new row item
        /// </summary>
        /// <param name="sender">Column View</param>
        /// <param name="e">ValidateRow Event Argurements</param>
        private void gridViewPurchaseBook_ValidateRow(object sender, ValidateRowEventArgs e)
        {
            if (_isNew)
            {
                ColumnView view = sender as ColumnView;
                CT_PurchaseBookDTO subconDTO = e.Row as CT_PurchaseBookDTO;
                string errorMessage;
                string fieldName;
                if (_purchaseBookBUS.ValidatePurchaseBook(subconDTO, out errorMessage, out fieldName))
                {
                    long consID = _purchaseBookBUS.CreatePurchaseBook(subconDTO);
                    if (consID == 0)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, Constants.CREATE_FAIL);
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, "Bạn Đã Tạo Mới Phiếu Mua Hàng Thành Công!");
                        RemoveRedoHistory();
                        subconDTO.PurchaseBookID = consID;
                        subconDTO.History = HistoryLevel.ADD;
                        _listHistory.Add(subconDTO);
                    }
                    _isNew = false;
                    LoadActivePurchaseBook();
                }
                else
                {
                    e.Valid = false;
                    view.ClearColumnErrors();
                    view.SetColumnError(view.Columns[fieldName], errorMessage, ErrorType.Warning);
                    DialogResult result = XtraMessageBox.Show(errorMessage + "\nBạn có muốn nhập lại thông tin", Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (result == DialogResult.No)
                    {
                        _isNew = false;
                        e.Valid = true;
                        LoadActivePurchaseBook();
                    }
                    else
                    {
                        view.FocusedColumn = view.Columns[fieldName];
                    }
                }
            }
            else
            {
                LoadActivePurchaseBook();
            }
        }

        /// <summary>
        /// Using to edit a PurchaseBook
        /// </summary>
        /// <param name="sender">ColumhView</param>
        /// <param name="e">CellValue changed event argurements</param>
        private void gridViewPurchaseBook_CellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            if(e.Column.FieldName == "MaterialID")
            {
                var material = repositoryItemLookUpEditMaterial.GetDataSourceRowByKeyValue(e.Value) as CT_MaterialDTO;
                gridViewPurchaseBook.SetRowCellValue(e.RowHandle, gridViewPurchaseBook.Columns["Unit"], material.Unit);
                gridViewPurchaseBook.SetRowCellValue(e.RowHandle, gridViewPurchaseBook.Columns["Price"], material.LastPrice);
            }
            if (e.Column.FieldName == "Quantity" || e.Column.FieldName == "Price")
            {
                CT_PurchaseBookDTO purechasebook = gridViewPurchaseBook.GetRow(e.RowHandle) as CT_PurchaseBookDTO;
                long totalCost = (long) purechasebook.Quantity * purechasebook.Price;
                gridViewPurchaseBook.SetRowCellValue(e.RowHandle, gridViewPurchaseBook.Columns["TotalCost"], totalCost);
            }
            if (!_isNew)
            {
                ColumnView view = sender as ColumnView;
                int currentRow = e.RowHandle;
                CT_PurchaseBookDTO consDTO = gridViewPurchaseBook.GetRow(currentRow) as CT_PurchaseBookDTO;
                CT_PurchaseBookDTO backupCons = _purchaseBookBUS.GetPurchaseBookByID(consDTO.PurchaseBookID);
                string errorMessage;
                string fieldName;
                if (_purchaseBookBUS.ValidatePurchaseBook(consDTO, out errorMessage, out fieldName))
                {
                    bool success = _purchaseBookBUS.UpdatePurchaseBook(consDTO);
                    if (!success)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, Constants.UPDATE_FAIL);
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, "Bạn Đã Cập Nhật Thông Tin Phiếu Mua Hàng Thành Công!");
                        RemoveRedoHistory();
                        backupCons.History = HistoryLevel.EDIT;
                        _listHistory.Add(backupCons);
                    }
                    _isNew = false;
                    LoadActivePurchaseBook();
                }
                else
                {
                    view.ClearColumnErrors();
                    view.SetColumnError(view.Columns[fieldName], errorMessage, ErrorType.Warning);
                    DialogResult result = XtraMessageBox.Show(errorMessage + "\nBạn có muốn nhập lại thông tin", Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                    if (result == DialogResult.No)
                    {
                        LoadActivePurchaseBook();
                    }
                    else
                    {
                        view.FocusedColumn = view.Columns[fieldName];
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// Allow User Edit Data
        /// </summary>
        private void AllowEditorNot()
        {
            if (_isAllowEdit)
            {
                alertControlMain.Show(this, Constants.CONFIRM, Constants.DISABLE_EIT_MESSAGE);
                _isAllowEdit = false;
                gridViewPurchaseBook.OptionsBehavior.Editable = false;
                barButtonItemAllowEdit.Caption = Constants.ALLOW_EIT;
            }
            else
            {
                DialogResult result = XtraMessageBox.Show(Constants.ALLOW_EIT_MESSAGE, Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (result == DialogResult.Yes)
                {
                    _isAllowEdit = true;
                    gridViewPurchaseBook.OptionsBehavior.Editable = true;
                    barButtonItemAllowEdit.Caption = Constants.DISABLE_EIT;
                }
            }
        }

        /// <summary>
        /// Load Data for Reporsity Items
        /// </summary>
        private void LoadRepositoryItems()
        {
            gridViewPurchaseBook.NewItemRowText = "Click Vào Đây Để Tạo Mới Phương Tiện!";

            SupplierBUS supplierBUS = new SupplierBUS();
            repositoryItemLookUpEditDebt.DataSource = supplierBUS.LoadSupplier(true);

            ConstructionBUS consBUS = new ConstructionBUS();
            repositoryItemLookUpEditConstruction.DataSource = consBUS.LoadConstruction(true);

            WarehouseBUS whBUS = new WarehouseBUS();
            repositoryItemLookUpEditWarehouse.DataSource = whBUS.LoadWarehouse(true);

            VehicleBUS vehicleBUS = new VehicleBUS();
            repositoryItemLookUpEditVehicle.DataSource = vehicleBUS.LoadVehicle(true);

            CommonBUS commonBUS = new CommonBUS();
            repositoryItemLookUpEditMaterial.DataSource = commonBUS.LoadMaterial(true);
            repositoryItemLookUpEditGroupMaterial.DataSource = commonBUS.LoadGroupMaterial(true);
        }

        /// <summary>
        /// Load active PurchaseBooks
        /// </summary>
        private void LoadActivePurchaseBook()
        {
            LoadPurchaseBook(true);
        }

        /// <summary>
        /// Load both active and inactive PurchaseBooks
        /// </summary>
        private void LoadAllPurchaseBook()
        {
            LoadPurchaseBook(false);
        }

        /// <summary>
        /// Function is called to load PurchaseBooks
        /// </summary>
        /// <param name="isactive">Load all PurchaseBook or just active PurchaseBook</param>
        private void LoadPurchaseBook(bool isactive)
        {
            _listSubcons = _purchaseBookBUS.LoadPurchaseBook(isactive);
            cTPurchaseBookDTOBindingSource.DataSource = _listSubcons;
        }

        /// <summary>
        /// Delete PurchaseBook Forever
        /// </summary>
        private void DeletePurchaseBook()
        {
            int[] numOfSelectedRows = gridViewPurchaseBook.GetSelectedRows();
            if (numOfSelectedRows.Length > 0)
            {
                CT_PurchaseBookDTO purbookDTO = gridViewPurchaseBook.GetRow(numOfSelectedRows[0]) as CT_PurchaseBookDTO;
                if (purbookDTO.IsConfirm)
                {
                    XtraMessageBox.Show("Không Thể Xóa Phiếu Mua Hàng Này\nVì Phiếu Mua Hàng Này Đã Được Xác Nhận!", Constants.ALERT, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
                else
                {
                    DialogResult result = XtraMessageBox.Show("Nếu Phiếu Mua Hàng Này Thì Toàn Bộ Dữ Liệu Liên Quan Sẽ Đều Bị Xóa Bỏ!\nBạn Có Chắc Muốn Xóa Vĩnh Viễn Phiếu Mua Hàng Này Không?", Constants.ALERT, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                    if (result == DialogResult.Yes)
                    {
                        CT_PurchaseBookDTO backuppurbook = _purchaseBookBUS.GetPurchaseBookByID(purbookDTO.PurchaseBookID);
                        bool success = _purchaseBookBUS.DeletePurchaseBook(purbookDTO.PurchaseBookID);
                        if (!success)
                        {
                            alertControlMain.Show(this, Constants.ALERT_ERROR, "Không Thể Xóa Thành Công Phiếu Mua Hàng");
                        }
                        else
                        {
                            alertControlMain.Show(this, Constants.CONFIRM, "Bạn Đã Xóa Phiếu Mua Hàng Thành Công");
                            RemoveRedoHistory();
                            backuppurbook.History = HistoryLevel.DELETE;
                            _listHistory.Add(backuppurbook);
                        }
                    }
                }
                
            }
            LoadActivePurchaseBook();
        }

        /// <summary>
        /// After undo, item will change status to waiting for redo.
        /// But after new action work, all items wating for redo must be remove
        /// </summary>
        private void RemoveRedoHistory()
        {
            for (int i = 0; i < _listHistory.Count; i++)
            {
                var cons = _listHistory[i];
                if (cons.History.ToString().Contains(Constants.UNDO))
                {
                    _listHistory.Remove(cons);
                    i--;
                }
            }
        }

        /// <summary>
        /// Undo user action
        /// </summary>
        private void Undo()
        {
            int numHistoryItems = _listHistory.Count;
            for (int i = numHistoryItems; i > 0; i--)
            {
                var undoItem = _listHistory[i - 1];
                switch (undoItem.History)
                {
                    case HistoryLevel.ADD:
                        _purchaseBookBUS.DeletePurchaseBook(undoItem.PurchaseBookID);
                        _listHistory[i - 1].History = HistoryLevel.UNDO_ADD;
                        LoadActivePurchaseBook();
                        return;
                    case HistoryLevel.EDIT:
                        _listHistory[i - 1] = _purchaseBookBUS.GetPurchaseBookByID(undoItem.PurchaseBookID);
                        _listHistory[i - 1].History = HistoryLevel.UNDO_EDIT;
                        _purchaseBookBUS.UpdatePurchaseBook(undoItem);
                        LoadActivePurchaseBook();
                        return;
                    case HistoryLevel.DELETE:
                        long oldConsID = _listHistory[i - 1].PurchaseBookID;
                        long newConsID = _purchaseBookBUS.CreatePurchaseBook(undoItem);
                        if (newConsID != 0)
                        {
                            foreach (var item in _listHistory)
                            {
                                if (item.PurchaseBookID == oldConsID)
                                {
                                    item.PurchaseBookID = newConsID;
                                }
                            }
                            _listHistory[i - 1].History = HistoryLevel.UNDO_DELETE;
                        }
                        LoadActivePurchaseBook();
                        return;
                    case HistoryLevel.UNDO_ADD:
                        break;
                    case HistoryLevel.UNDO_EDIT:
                        break;
                    case HistoryLevel.UNDO_DELETE:
                        break;
                }
            }
        }

        /// <summary>
        /// Redo user action
        /// </summary>
        private void Redo()
        {
            int numHistoryItems = _listHistory.Count;
            for (int i = 0; i < numHistoryItems; i++)
            {
                var redoItem = _listHistory[i];
                switch (redoItem.History)
                {
                    case HistoryLevel.ADD:
                        break;
                    case HistoryLevel.EDIT:
                        break;
                    case HistoryLevel.DELETE:
                        break; ;
                    case HistoryLevel.UNDO_ADD:
                        long oldConsID = _listHistory[i].PurchaseBookID;
                        long newConsID = _purchaseBookBUS.CreatePurchaseBook(redoItem);
                        if (newConsID != 0)
                        {
                            foreach (var item in _listHistory)
                            {
                                if (item.PurchaseBookID == oldConsID)
                                {
                                    item.PurchaseBookID = newConsID;
                                }
                            }
                            _listHistory[i].History = HistoryLevel.ADD;
                        }
                        LoadActivePurchaseBook();
                        return;
                    case HistoryLevel.UNDO_EDIT:
                        _listHistory[i] = _purchaseBookBUS.GetPurchaseBookByID(redoItem.PurchaseBookID);
                        _listHistory[i].History = HistoryLevel.EDIT;
                        _purchaseBookBUS.UpdatePurchaseBook(redoItem);
                        LoadActivePurchaseBook();
                        return;
                    case HistoryLevel.UNDO_DELETE:
                        _purchaseBookBUS.DeletePurchaseBook(redoItem.PurchaseBookID);
                        _listHistory[i].History = HistoryLevel.DELETE;
                        LoadActivePurchaseBook();
                        return;
                }
            }
        }
    }
}